package ua.kozlovskyi.ClassLoader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

/**
 * Created by Kozlovskyi.
 */
public class DynamicClassOverloader extends ClassLoader {
    private java.util.Map classesHash= new java.util.HashMap();

    public final String[] classPath;
    //---------------------------------------------------------------
    public DynamicClassOverloader(String[] classPath) {
        this.classPath= classPath;
    }
    //----------------------------------------------------------------
    protected synchronized Class loadClass(String name,boolean resolve)
            throws ClassNotFoundException {
        Class result= findClass(name);
        if (resolve) resolveClass(result);
        return result;
    }//----------------------------------------------------------------
    protected Class findClass(String name) throws ClassNotFoundException {
        Class result = (Class)classesHash.get(name);
        if (result!=null) {
            System.out.println("% Class "+name+" found in cache");
            return result;
        }
        File f = findFile(name.replace('.','/'),".class");
        System.out.println("% Class "+name+(f==null?"":" found in "+f));
        if (f == null) {
            return findSystemClass(name);
        }
        try {
            byte[] classBytes= loadFileAsBytes(f);
            result= defineClass(name,classBytes,0,classBytes.length);
        } catch (IOException e) {
            throw new ClassNotFoundException("Cannot load class "+name+": "+e);
        } catch (ClassFormatError e) {
            throw new ClassNotFoundException("Format of class file incorrect for class "+name+": "+e);
        }
        classesHash.put(name,result);
        return result;
    }//-----------------------------------------------------------------
    protected java.net.URL findResource(String name) {
        File f= findFile(name,"");
        if (f==null) return null;
        try {
            return f.toURL();
        } catch (java.net.MalformedURLException e) {
            return null;
        }
    }//-----------------------------------------------------------------
    private File findFile(String name, String extension) {
        for (int k=0; k<classPath.length; k++) {
            File f= new File((new File(classPath[k])).getPath()+File.separatorChar+name.replace('/',File.separatorChar)+extension);
            if (f.exists()) return f;
        }
        return null;
    }//------------------------------------------------------------------
    private static byte[] loadFileAsBytes(File file) throws IOException {
        byte[] result= new byte[(int)file.length()];
        FileInputStream f= new FileInputStream(file);
        try {
            f.read(result,0,result.length);
        } finally {
            try {
                f.close();
            } catch (Exception e) {
            };
        }
        return result;
    }//------------------------------------------------------------------
}//End class DynamicClassOverloader
